/*
 * callbacks.c
 * Copyright (C) Pietro Pilolli 2010 <pilolli@fbk.eu>
 * 
 * spotlighter is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * spotlighter is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include "callbacks.h"
#include "utils.h"
#include <math.h>
#include <stdlib.h>
#include <gdk/gdkkeysyms.h>

#include <cairo.h>

#define BACKGROUND_COLOR "000000FF"
#define SPOTLIGHTER_COLOR "00000000" 


/* main cairo context */
static cairo_t *cr = NULL;

/* Used to shape input mask */
static cairo_t *shape_cr = NULL;
static GdkBitmap* shape = NULL;

static gint screen_width;
static gint screen_height;

static gdouble minx;
static gdouble maxx;
static gdouble miny;
static gdouble maxy;


static gboolean ellipse = TRUE;

static GdkCursor* cursor = NULL;

static gint zone = 5;

static gboolean first= TRUE;


/* Quit the program */
void quit()
{
  if (cr)
    {
      cairo_destroy(cr); 
    } 
  if (shape)
    {  
      g_object_unref (G_OBJECT(shape));
    }
  if (shape_cr)
    {
      cairo_destroy(shape_cr);
    }
  if (cursor)
    {
      gdk_cursor_unref(cursor);
    }
  gtk_main_quit ();
  exit(1);
}


/* Destroy the program */
G_MODULE_EXPORT gboolean 
destroy (GtkWidget *widget, gpointer data)
{
  quit();
  return TRUE;
}


/* Reset the shape used for the input mask */
void reset_shape()
{
  if (shape_cr)
    {
      cairo_set_operator(shape_cr,CAIRO_OPERATOR_SOURCE);
      cairo_set_source_rgba (shape_cr, 1, 1, 1, 1);
      cairo_paint(shape_cr);
      cairo_stroke(shape_cr);
    }
}


/* Draw the spotlighter hole */
void draw(cairo_t* cr, gdouble x, gdouble y, gdouble width, gdouble height, gchar* color)
{
  if (cr)
    {
      if (!ellipse)
	{
	  cairo_draw_rectangle(cr, minx, miny, maxx - minx, maxy - miny, color);
	}
      else
	{
	  cairo_draw_ellipse(cr, minx, miny, maxx - minx, maxy - miny, color);
	} 
    }
}


G_MODULE_EXPORT gboolean 
on_window_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
{
  gint is_fullscreen = gdk_window_get_state (widget->window) & GDK_WINDOW_STATE_FULLSCREEN;
  if (!is_fullscreen>0)
    {
      return TRUE;
    }
  if (!cr)
    {
      screen_width = gdk_screen_width();
      screen_height = gdk_screen_height();
      cr = gdk_cairo_create(widget->window);

      /* initialize the cairo context pen options */
      cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
      cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
      cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
    }

  color_window(cr, BACKGROUND_COLOR, screen_width);
  
  /* Initialize the shape for the input mask */
  if (!shape)
    {
      shape = gdk_pixmap_new (NULL, screen_width, screen_height, 1);
    }
  if (!shape_cr)
    {
      shape_cr = gdk_cairo_create(shape);
    }
  
  return TRUE;
}


gboolean is_in_rectangle(gdouble x, gdouble y, gdouble minx, gdouble miny, gdouble maxx, gdouble maxy)
{
  if ((minx<x)&&(x<maxx)&&(miny<y)&&(y<maxy))
    { 
      return TRUE;
    }
  return FALSE;
}


void discriminate_zone(gdouble x, gdouble y)
{
  gint tollerance = 30;
  zone = 5;
  GdkCursorType type = GDK_FLEUR;
  if (is_in_rectangle(x, y, minx-tollerance, miny-tollerance, maxx+tollerance, maxy+tollerance))
    {
      double deltax = (maxx-minx)/4;
      double deltay = (maxy-miny)/4;
      /*
        This is the topologic zone explained

	1|1
	---------
	|4|1|1|6|
	---------
	0|0|5|5|2|2
	---------
	0|0|5|5|2|2
	---------
	|8|3|3|7|
	---------
	3|3
      */
   
      if (is_in_rectangle(x,y,minx+deltax,miny-tollerance,maxx-deltax,miny+deltay))
	{
	  zone=1;
	  type = GDK_TOP_SIDE;
	}
      else if (is_in_rectangle(x,y,minx+deltax,maxy-deltay,maxx-deltax,maxy+tollerance))
	{
	  zone=3;
	  type = GDK_BOTTOM_SIDE;
	}
      else if (is_in_rectangle(x,y,minx-tollerance, miny+deltay,minx+deltax,maxy-deltay))
	{
	  zone=0;
	  type = GDK_LEFT_SIDE;
	}
      else if (is_in_rectangle(x,y,maxx-deltax, miny+deltay,maxx+tollerance,maxy-deltay))
	{ 
	  zone=2;
	  type = GDK_RIGHT_SIDE;
	}
      else if (is_in_rectangle(x,y,minx+deltax, miny+deltay,maxx-deltax,maxy-deltay))
	{
	  zone=5;
	}
      else if (is_in_rectangle(x,y,minx, miny,minx+deltax,miny+deltay))
	{
	  zone=4;
	  type = GDK_TOP_LEFT_CORNER;
	}  
      else if (is_in_rectangle(x,y,maxx-deltax, miny,maxx,miny+deltay))
	{
	  zone=6;
	  type = GDK_TOP_RIGHT_CORNER;
	}  
      else if (is_in_rectangle(x,y,maxx-deltax, maxy-deltay,maxx,maxy))
	{
	  zone=7;
	  type = GDK_BOTTOM_RIGHT_CORNER;
	}  
      else if (is_in_rectangle(x,y,minx, maxy-deltay,minx+deltax,maxy))
	{
	  zone=8;
	  type = GDK_BOTTOM_LEFT_CORNER;
	}  
    }
  if (cursor)
    {
      gdk_cursor_unref(cursor);
    }
  cursor = gdk_cursor_new(type);
 
}


gboolean is_above_close_button(gint x, gint y)
{
  if ((x>screen_width-25)&&(y<25))
    {
      return TRUE;
    }
  return FALSE;
}


G_MODULE_EXPORT gboolean 
on_window_button_press_event (GtkWindow *window, GdkEventButton *event, gpointer data)
{
  if (is_above_close_button(event->x, event->y))
    {
      quit();
    }
  if (first)
    {
      gint tmpx;
      gint tmpy;
      gdk_display_get_pointer (gdk_display_get_default (), NULL, &tmpx, &tmpy, NULL);
      gdouble centerx = (gdouble) tmpx;
      gdouble centery = (gdouble) tmpy;
      maxx = centerx + 150;
      maxy = centery + 100;
      minx = centerx-150;
      miny = centery-100;
	  first = FALSE;
	}
#ifndef _WIN32
  gtk_widget_input_shape_combine_mask(GTK_WIDGET(window), NULL, 0, 0);
#else
  //acquire the mouse
#endif
	
  return TRUE;
}


G_MODULE_EXPORT gboolean 
on_window_motion_event (GtkWindow *window, GdkEventButton *event, gpointer data)
{
  GdkModifierType state = (GdkModifierType) event->state; 
  /* only if button1 is not pushed */
  if (!(state & GDK_BUTTON1_MASK))
    {
      if (is_above_close_button(event->x, event->y))
        {
          gdk_window_set_cursor (GTK_WIDGET(window)->window, NULL);
        }
      else
        {
          discriminate_zone(event->x,event->y);  
          gdk_window_set_cursor (GTK_WIDGET(window)->window, cursor);
        }
    }
  return TRUE;
}


G_MODULE_EXPORT gboolean 
on_window_button_release_event (GtkWindow *window, GdkEventButton *ev, gpointer data)
{
  /* only button1 allowed */
  if (!(ev->button==1))
    {
      return FALSE;
    }

  gint spotlighter_minimum_size = 60;
  gdk_window_set_cursor (GTK_WIDGET(window)->window, NULL);
  
  if (cr)
    { 
      color_window(cr, BACKGROUND_COLOR, screen_width);
    }

  if (zone==5)
    {
      gdouble centerdeltax = ev->x - (minx + ((maxx-minx)/2));
      gdouble centerdeltay = ev->y - (miny + ((maxy-miny)/2));
      minx = minx + centerdeltax;
      miny = miny + centerdeltay;
      maxx = maxx + centerdeltax;
      maxy = maxy + centerdeltay; 
    }
  else if (zone==1)
    {
      if (fabs(miny-ev->y)>spotlighter_minimum_size)
	{
	  miny = ev->y;
	}
    }
  else if (zone==3)
    {
      if (fabs(miny-ev->y)>spotlighter_minimum_size)
	{
	  maxy = ev->y;
	}
    }
  else if (zone==0)
    {
      if (fabs(minx-ev->x)>spotlighter_minimum_size)
	{
	  minx= ev->x;
	}
    }
  else if (zone==2)
    {
      if (fabs(minx-ev->x)>spotlighter_minimum_size)
	{
	  maxx= ev->x;
	}
    }
  else if (zone==4)
    {
      if ((fabs(maxy-ev->y)>spotlighter_minimum_size) && (fabs(maxx-ev->x)>spotlighter_minimum_size))
	{
	  minx= ev->x;
	  miny= ev->y; 
	}
    }
  else if (zone==6)
    {
      if ((fabs(maxy-ev->y)>spotlighter_minimum_size) && (fabs(minx-ev->x)>spotlighter_minimum_size))
	{
	  miny= ev->y; 
	  maxx= ev->x;
	}
    }
  else if (zone==7)
    {
      if ((fabs(miny-ev->y)>spotlighter_minimum_size) && (fabs(minx-ev->x)>spotlighter_minimum_size))
	{
	  maxx= ev->x;
	  maxy= ev->y; 
	}
    }
  else if (zone==8)
    {
      if ((fabs(miny-ev->y)>spotlighter_minimum_size) && (fabs(maxx-ev->x)>spotlighter_minimum_size))
	{
	  maxy= ev->y; 
	  minx= ev->x;
	}
    }

  draw(cr, minx, miny, maxx - minx, maxy - miny, SPOTLIGHTER_COLOR);

  reset_shape();
  draw(shape_cr, minx, miny, maxx - minx, maxy - miny, SPOTLIGHTER_COLOR);
  /* this allow the mouse focus below the transparent hole */
#ifndef _WIN32
  gtk_widget_input_shape_combine_mask(GTK_WIDGET(window), shape, 0, 0); 
#else
  gtk_widget_shape_combine_mask(GTK_WIDGET(window), shape, 0, 0);
  //release the mouse	
#endif
 
  return TRUE;
}


G_MODULE_EXPORT gboolean 
on_window_destroy_event (GtkWindow *self, GdkEvent *arg0, gpointer user_data)
{
  quit();
  return TRUE;
}



